import Events from "@/Events.ts";
import useDebounce from './useDebounce.js'
import type DocumentEditor from './Document.ts'


interface Position {
    x: number,
    y: number
}

export default class MouseEvent extends Events {
    parent: DocumentEditor
    MouseDownEvent: Function
    MouseMoveEvent: Function
    MouseUpEvent: Function
    DragState: Boolean
    MouseDownState: Boolean
    DragDownCache: Position
    MouseMoveCache: Position
    RefreshHoverId: Function
    MouseDownCache: null | string
    DragToState: null | string
    DragElementCache: null | string
    AddType: null | string
    GetComponentField(Component) {
        const BoardStop = document.getElementById('BoardStop');
        const element = Component.vnode.el;
        if (!element.getAttribute) return null;
        const id = Component?.ctx?.config?.field;
        if (id && this.parent.GetRuleById(id)) {
            return id;
        } else if (element?.getAttribute('id') == 'BoardStop' || element.contains(BoardStop)) {
            return null
        } else {
            return this.GetComponentField(Component.parent)
        }
    }
    GetTargetId(element) {
        const BoardStop = document.getElementById('BoardStop');
        const Component = element.__vueParentComponent;
        if (!Component) return null;
        const id = Component?.ctx?.config?.field;
        if (id && this.parent.GetRuleById(id)) {
            return id;
        } else if (element.getAttribute('id') == 'BoardStop' || element.contains(BoardStop)) {
            return null
        } else {
            return this.GetComponentField(Component.parent)
        }
    }
    constructor(parent: DocumentEditor) {
        super()

        this.parent = parent

        // 中间函数，为防止事件无法注销
        this.MouseDownEvent = e => this.MouseDown(e)
        this.MouseMoveEvent = e => this.MouseMove(e)
        this.MouseUpEvent = e => this.MouseUp(e)
        document.addEventListener('mousedown', this.MouseDownEvent as any, true);
        document.addEventListener('mousemove', this.MouseMoveEvent as any, true);
        document.addEventListener('mouseup', this.MouseUpEvent as any, true);

        // 拖拽状态
        this.DragState = false;
        // 鼠标按下状态
        this.MouseDownState = false;
        // 鼠标位置缓存
        this.DragDownCache = { x: 0, y: 0 };
        this.MouseMoveCache = { x: 0, y: 0 };
        // 鼠标按下时,拖住的元素缓存
        this.MouseDownCache = null;

        // 目标元素拖拽状态
        this.DragToState = null;
        // 目标元素对象缓存
        this.DragElementCache = null;

        // 基于防抖 建立的通过 X Y 值 更新鼠标所在元素的方法, 用于鼠标滚轮滚动后,更新 Hover 事件
        this.RefreshHoverId = useDebounce(() => {
            const ele = document.elementFromPoint(this.MouseMoveCache.x, this.MouseMoveCache.y);
            const id = this.GetTargetId(ele);
            if (!this.DragState) {
                this.parent.HoverItemId.value = id;
            } else if (this.DragState && !!id) {
                const CellRule = this.parent.GetRuleById(id);
                const Rule = this.parent.GetRuleType(CellRule.type);
                const IndicateEle = this.parent.GetEle(id);
                // document.querySelectorAll(`[data-field="${id}"]`)[0];
                this.parent.IndicateRect.value = IndicateEle?.getBoundingClientRect();
                this.parent.IndicateId.value = id;
                const style = window.getComputedStyle(IndicateEle);
                const ParentNode = IndicateEle.parentNode as Element;
                const ParentStyle = window.getComputedStyle(ParentNode);
                if (style.display == 'inline' || style.display == 'inline-block' || (ParentStyle.display == 'flex' && (ParentStyle.flexDirection == 'row' || ParentStyle.flexDirection == 'row-reverse'))) {
                    this.Horizontal(Rule, this.MouseMoveCache.x);
                } else {
                    this.Vertical(Rule, this.MouseMoveCache.y);
                }
            }
        }, 300);


    }
    AddMouseEvent(event, item) {
        this.DragDownCache.x = event.pageX;
        this.DragDownCache.y = event.pageY;

        this.parent.MouseMoveCache.value.x = event.pageX;
        this.parent.MouseMoveCache.value.y = event.pageY;

        this.MouseDownState = true;
        this.AddType = item.type;
    }
    MouseDown(event) {
        this.DragDownCache.x = event.pageX;
        this.DragDownCache.y = event.pageY;

        this.parent.MouseMoveCache.value.x = event.pageX;
        this.parent.MouseMoveCache.value.y = event.pageY;

        const id = this.GetTargetId(event.target);
        if (id) {
            this.MouseDownState = true;
            var IsActiveChild = this.parent.IsActiveChild(id);
            if (IsActiveChild) {
                this.MouseDownCache = this.parent.ActiveId.value;
            } else {
                this.MouseDownCache = id;
            };
        };
    }
    // 纵向
    Vertical(Rule, y) {
        const Height = this.parent.IndicateRect.value.height;
        const Top = this.parent.IndicateRect.value.top;

        if (Rule.DragType == 'Ele') {
            const unitHieght = Height / 2;
            if (y < unitHieght + Top) {
                this.parent.IndicateType.value = 'UP'
            } else {
                this.parent.IndicateType.value = 'DOWN'
            }
        } else if (Rule.DragType == 'Box') {
            const unitHieght = Height / 3;
            if (y < unitHieght + Top) {
                this.parent.IndicateType.value = 'UP'
            } else if (y > unitHieght * 2 + Top) {
                this.parent.IndicateType.value = 'DOWN'
            } else {
                this.parent.IndicateType.value = 'IN'
            }
        } else if (Rule.DragType == 'OnlyIn') {
            this.parent.IndicateType.value = 'IN'
        }
    }
    // 横向
    Horizontal(Rule, x) {
        const Width = this.parent.IndicateRect.value.width;
        const Left = this.parent.IndicateRect.value.left;

        if (Rule.DragType == 'Ele') {
            const unitHieght = Width / 2;
            if (x < unitHieght + Left) {
                this.parent.IndicateType.value = 'LEFT'
            } else {
                this.parent.IndicateType.value = 'RIGHT'
            }
        } else if (Rule.DragType == 'Box') {
            const unitHieght = Width / 3;
            if (x < unitHieght + Left) {
                this.parent.IndicateType.value = 'LEFT'
            } else if (x > unitHieght * 2 + Left) {
                this.parent.IndicateType.value = 'RIGHT'
            } else {
                this.parent.IndicateType.value = 'IN'
            }
        } else if (Rule.DragType == 'OnlyIn') {
            this.parent.IndicateType.value = 'IN'
        }

    }
    MouseMove(event) {
        const x = event.pageX;
        const y = event.pageY;

        this.MouseMoveCache.x = x;
        this.MouseMoveCache.y = y;
        this.parent.MouseMoveCache.value.x = x;
        this.parent.MouseMoveCache.value.y = y;

        if (this.DragState) {
            const id = this.GetTargetId(event.target);
            if (id) {
                const CellRule = this.parent.GetRuleById(id);
                const Rule = this.parent.GetRuleType(CellRule.type);
                const IndicateEle = this.parent.GetEle(id);
                // document.querySelectorAll(`[data-field="${id}"]`)[0];
                this.parent.IndicateRect.value = IndicateEle?.getBoundingClientRect();
                this.parent.IndicateId.value = id;
                const style = window.getComputedStyle(IndicateEle);
                const ParentNode = IndicateEle.parentNode as Element;
                const ParentStyle = window.getComputedStyle(ParentNode);

                if (style.display == 'inline' || style.display == 'inline-block' || (ParentStyle.display == 'flex' && (ParentStyle.flexDirection == 'row' || ParentStyle.flexDirection == 'row-reverse'))) {
                    this.Horizontal(Rule, x);
                } else {
                    this.Vertical(Rule, y);
                }
            }
        } else {
            this.parent.HoverItemId.value = this.GetTargetId(event.target);
        }

        if (this.MouseDownState) {
            if (!this.DragState) {
                if (Math.abs(this.DragDownCache.x - event.pageX) > 5 || Math.abs(this.DragDownCache.y - event.pageY) > 5) {
                    // 开启 拖拽交互
                    this.DragState = true;
                    // 开启遮罩,阻挡拖拽
                    const DragMarkele = this.parent.GetEle(this.MouseDownCache);
                    // document.querySelectorAll(`[data-field="${this.MouseDownCache}"]`)[0];
                    this.parent.DragMarkRect.value = DragMarkele?.getBoundingClientRect();

                    // 在此处处理 不可移动 Slot 子集容器
                    const CellRule = this.parent.GetRuleById(this.MouseDownCache);
                    if (CellRule) {
                        const Rule = this.parent.GetRuleType(CellRule.type);
                        if (Rule.CanNotMove) {
                            this.DragState = false;
                        }
                    }

                    if (this.MouseDownCache) {
                        const CellRule = this.parent.GetRuleById(this.MouseDownCache);
                        const Rule = this.parent.GetRuleType(CellRule.type);
                        if (CellRule.props.title) {
                            this.parent.MouseMoveCache.value.name = CellRule.props.title;
                        } else {
                            this.parent.MouseMoveCache.value.name = Rule.name;
                        }
                        this.parent.MouseMoveCache.value.icon = Rule.icon;
                    } else if (this.AddType) {
                        const Rule = this.parent.GetRuleType(this.AddType);
                        this.parent.MouseMoveCache.value.name = Rule.name;
                        this.parent.MouseMoveCache.value.icon = Rule.icon;
                    }

                    // 清空 交互结果
                    this.parent.HoverItemId.value = null;
                    this.parent.ActiveId.value = null;
                };
            }
        }
    }
    MouseUp(event) {
        if (!this.DragState && this.MouseDownState) {
            // 未开启拖拽事件, 执行点击事件
            var id = this.GetTargetId(event.target);
            if (id) { this.parent.ActiveId.value = id };
        } else {
            // 已开启拖拽事件, 执行拖拽结果
            if (this.parent.IndicateId.value && this.parent.IndicateType.value) {
                if (this.MouseDownCache) {
                    this.parent.MoveItem(this.MouseDownCache, this.parent.IndicateId.value, this.parent.IndicateType.value, event.altKey)
                } else if (this.AddType) {
                    this.parent.AddItem(this.AddType, this.parent.IndicateId.value, this.parent.IndicateType.value)
                }
            }
        }
        this.parent.MouseMoveCache.value = { x: 0, y: 0, name: '', icon: '' };
        this.MouseDownCache = null;
        this.parent.IndicateType.value = null;
        this.parent.IndicateRect.value = null;
        this.parent.IndicateId.value = null;
        this.parent.DragMarkRect.value = null;
        this.DragState = false;
        this.MouseDownState = false;

    }
    // 注销
    destroy() {
        this.off(null, null);
        document.removeEventListener('mousedown', this.MouseDownEvent as any, true);
        document.removeEventListener('mousemove', this.MouseMoveEvent as any, true);
        document.removeEventListener('mouseup', this.MouseUpEvent as any, true);
    }
}
